/*
 *
 *      Copyright (c) 2018-2025, scs All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the pig4cloud.com developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: scs
 *
 */

package com.zyh.scs.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zyh.scs.admin.api.constant.UserCardEnum;
import com.zyh.scs.admin.api.constant.UserCardStateEnum;
import com.zyh.scs.admin.api.constant.UserStateEnum;
import com.zyh.scs.admin.api.constant.UserTypeEnum;
import com.zyh.scs.admin.api.dto.*;
import com.zyh.scs.admin.api.entity.*;
import com.zyh.scs.admin.api.utils.UserTypeToNameUtil;
import com.zyh.scs.admin.api.vo.*;
import com.zyh.scs.admin.mapper.*;
import com.zyh.scs.admin.service.SysDeptService;
import com.zyh.scs.admin.service.SysMenuService;
import com.zyh.scs.admin.service.SysRoleService;
import com.zyh.scs.admin.service.SysUserService;
import com.zyh.scs.common.core.constant.CacheConstants;
import com.zyh.scs.common.core.constant.CommonConstants;
import com.zyh.scs.common.core.exception.ErrorCodes;
import com.zyh.scs.common.core.exception.OpenException;
import com.zyh.scs.common.core.exception.OpenResponseCode;
import com.zyh.scs.common.core.util.MsgUtils;
import com.zyh.scs.common.core.util.R;
import com.zyh.scs.common.security.service.ScsUser;
import com.zyh.scs.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author scs
 * @date 2017/10/31
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    private final SysMenuService sysMenuService;

    private final SysRoleMapper sysRoleMapper;

    private final SysDeptService sysDeptService;

    private final SysUserRoleMapper sysUserRoleMapper;

    private final CacheManager cacheManager;

    private final SysUserMapper sysUserMapper;

    private final SysRoleService sysRoleService;

    private final UserSealMapper userSealMapper;

    private final UserTransactionMapper userTransactionMapper;

    private final SysPostMapper sysPostMapper;

    private final UserAuthorityMapper userAuthorityMapper;

    private final UserDepartmentInfoMapper userDepartmentInfoMapper;

    private final UserPaymentMapper userPaymentMapper;

    private final RedisTemplate<String, Object> redisTemplate;

    private final RedissonClient redissonClient;


    @Override
    public List<UserCompanyVO> getCompany() {
        List<UserCompanyVO> dataList = new ArrayList<>();
        List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoMapper
                .selectList(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getApplyEvent, 2)
                        .eq(UserDepartmentInfo::getOrgStatus, 1));
        getUserDepart(userDepartmentInfoList, dataList, 1, null);
        return dataList;
    }

    @Override
    public List<UserCompanyVO> getOrganizational() {
        List<UserCompanyVO> dataList = new ArrayList<>();
        List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoMapper
                .selectList(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getApplyEvent, 2)
                        .eq(UserDepartmentInfo::getOrgStatus, 1));
        getUserDepart(userDepartmentInfoList, dataList, 1, null);
        return dataList;
    }

    @Override
    public List<UserCompanyVO> getDept(Long id) {
        UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectById(id);
        List<UserCompanyVO> dataList = new ArrayList<>();
        if (userDepartmentInfo != null && StrUtil.isNotBlank(userDepartmentInfo.getDeptId())) {
            List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoMapper
                    .selectList(Wrappers.<UserDepartmentInfo>lambdaQuery()
                            .eq(UserDepartmentInfo::getApplyEvent, 2)
                            .eq(UserDepartmentInfo::getOrgStatus, 1));
            if (userDepartmentInfoList.isEmpty()) {
                throw new OpenException(OpenResponseCode.DEPT_IS_NOT);
            }
            getUserDepart(userDepartmentInfoList, dataList, 2, userDepartmentInfo.getDeptId());
        } else {
            throw new OpenException(OpenResponseCode.DEPT_IS_NOT);
        }
        return dataList;
    }

    private static void getUserDepart(List<UserDepartmentInfo> userDepartmentInfoList, List<UserCompanyVO> dataList, Integer type, String deptId) {
        if (userDepartmentInfoList != null) {
            List<UserCompanyVO> list = userDepartmentInfoList.stream().map(a -> {
                UserCompanyVO userCompanyVO = new UserCompanyVO();
                BeanUtils.copyProperties(a, userCompanyVO);
                return userCompanyVO;
            }).toList();

            list.forEach(e -> {
                //判断当前id是否为其他数据的父id
                List<UserCompanyVO> childrenList = getChildrenList(e.getDeptId(), list);
                //设置子集,如果到了最后一级，那么直接设置为null，不展示这个属性即可
                e.setSiteDtoList(!childrenList.isEmpty() ? childrenList : null);
            });

            //获取所有的顶点数据，即最上层数据,该数据的pid为0
            //注意这个pid的数据类型，如果数据库为varchar则equals("0") 整型则为equals(0)
            List<UserCompanyVO> siteDtoParents = new ArrayList<>();
            if (type == 1) {
                siteDtoParents = list.stream().filter(org -> StrUtil.isNotBlank(org.getOrgLevel())).filter(t -> t.getOrgLevel().equals("1")).toList();
            }
            if (type == 2) {
                siteDtoParents = list.stream().filter(a -> StrUtil.isNotBlank(a.getParentId())).filter(t -> t.getParentId().equals(deptId)).toList();
            }
            dataList.addAll(siteDtoParents);
        }
    }

    //获取全部的子集合
    public static List<UserCompanyVO> getChildrenList(String id, List<UserCompanyVO> list) {
        //便利全部数据，将需要的数据过滤出来
        return list.stream().filter(a -> StrUtil.isNotBlank(a.getParentId())).filter(t -> t.getParentId().equals(id)).collect(Collectors.toList());
    }

    /**
     * 保存用户信息
     *
     * @param userUpdateDto DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserAddDto userUpdateDto) {
        SysUser sysUser = new SysUser();
        boolean userJobNumberExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserJobNumber, userUpdateDto.getUserJobNumber()).eq(SysUser::getPhone, userUpdateDto.getPhone()).eq(SysUser::getIsAdmin, "1").eq(SysUser::getDelFlag, "0"));
        if (userJobNumberExists) {
            throw new OpenException(OpenResponseCode.USER_JOB_NUMBER_IS_EXIST);
        }
        boolean userNameExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, userUpdateDto.getUsername()).eq(SysUser::getIsAdmin, "1").eq(SysUser::getDelFlag, "0"));
        if (userNameExists) {
            throw new OpenException(OpenResponseCode.USER_NAME_IS_EXIST);
        }
        BeanUtils.copyProperties(userUpdateDto, sysUser);

        if (userUpdateDto.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            sysUser.setCashState("2");
            sysUser.setCardState("2");
        } else {
            sysUser.setCardState("1");
            sysUser.setCashState("1");
        }
        sysUser.setLockFlag(StrUtil.isBlank(userUpdateDto.getLockFlag()) ? UserStateEnum.NORMAL.getCode() : userUpdateDto.getLockFlag());
        sysUser.setCreateBy(userUpdateDto.getUsername());
        sysUser.setUpdateBy(userUpdateDto.getUsername());
        sysUser.setPostId(userUpdateDto.getPostId());
        sysUser.setPasswordExpireFlag(UserStateEnum.NORMAL.getCode());
        //设置默认密码 用户名
        sysUser.setPassword(ENCODER.encode("Aa1234567"));
        sysUser.setDelFlag("0");
        sysUser.setDataSources("2");
        sysUser.setCashAccount(BigDecimal.ZERO);
        sysUser.setCardAccount(BigDecimal.ZERO);
        sysUser.setCreateTime(LocalDateTime.now());
        sysUser.setGuid(IdUtil.nanoId(20));
        //设置生成账户号
        sysUser.setUserAccount(UserTypeToNameUtil.setRechargeStream());
        if (StrUtil.isBlank(userUpdateDto.getThirdDeptId()) && userUpdateDto.getCompanyId() == null) {
            //新增默认部门
            sysUser.setDeptId(132L);
            sysUser.setThirdDeptId("132");
            //新增默认公司
            sysUser.setCompanyId(2L);
        }
        sysUser.setPullStatus(1);
        //添加时 判断是否存在该用户 依据：手机号，工号 其中一个有就失败
        // 判断工号是否存在 判断手机号是否存在
        baseMapper.insert(sysUser);
        return Boolean.TRUE;
    }

    @Override
    public Boolean addAuthority(AddAuthorityDTO addAuthorityDTO) {
        if (userAuthorityMapper.selectOne(Wrappers.<UserAuthority>lambdaQuery()
                .eq(StrUtil.isNotBlank(addAuthorityDTO.getGuid()), UserAuthority::getGuid, addAuthorityDTO.getGuid())
                .orderByDesc(UserAuthority::getCreateTime).last("limit 1")) != null) {
            throw new OpenException(OpenResponseCode.ROLE_IS);
        }
        SysUser sysUser = sysUserMapper.selectByGuid(addAuthorityDTO.getGuid());
        UserAuthority userAuthority = new UserAuthority();
        userAuthority.setUserId(addAuthorityDTO.getUserId());
        userAuthority.setRoleId(addAuthorityDTO.getRoleId());
        userAuthority.setStatus(addAuthorityDTO.getStatus());
        userAuthority.setPhone(sysUser.getPhone());
        userAuthority.setDeptId(sysUser.getDeptId());
        userAuthority.setThirdDeptId(sysUser.getThirdDeptId());
        userAuthority.setCompanyId(sysUser.getCompanyId());
        userAuthority.setUsername(sysUser.getUsername());
        userAuthority.setPostId(sysUser.getPostId());
        userAuthority.setGuid(sysUser.getGuid());
        userAuthorityMapper.insert(userAuthority);
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getUserId, sysUser.getUserId()));
        SysUserRole sysUserRole = new SysUserRole();
        if (sysUserRoleMapper.selectOne(Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getUserId, sysUser.getUserId())
                .eq(SysUserRole::getRoleId, addAuthorityDTO.getRoleId())) == null) {
            sysUserRole.setUserId(sysUser.getUserId());
            sysUserRole.setRoleId(addAuthorityDTO.getRoleId());
            sysUserRoleMapper.insert(sysUserRole);
        }
        sysUser.setPassword(ENCODER.encode("Aa1234567"));
        sysUser.setRoleId(addAuthorityDTO.getRoleId());
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateToAuthority(AddAuthorityDTO addAuthorityDTO) {
        UserAuthority userAuthority = new UserAuthority();
        userAuthority.setRoleId(addAuthorityDTO.getRoleId());
        userAuthority.setStatus(addAuthorityDTO.getStatus());
        userAuthority.setId(addAuthorityDTO.getId());
        userAuthorityMapper.updateById(userAuthority);
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getUserId, addAuthorityDTO.getUserId()));
        if (addAuthorityDTO.getStatus().equals(UserStateEnum.NORMAL.getCode())) {
            sysUserRole.setUserId(addAuthorityDTO.getUserId());
            sysUserRole.setRoleId(addAuthorityDTO.getRoleId());
            sysUserRoleMapper.insert(sysUserRole);
        }
        SysUser sysUser = sysUserMapper.selectById(addAuthorityDTO.getUserId());
        if (sysUser != null) {
            redisTemplate.delete("1:user_details::" + sysUser.getUsername());
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateAuthority(Long id) {
        UserAuthority userAuthority = userAuthorityMapper.selectById(id);
        SysUser sysUser = sysUserMapper.selectById(userAuthority.getUserId());
        if (sysUser.getIsAdmin() == 2) {
            throw new OpenException(OpenResponseCode.ADMIN_IS_FAIL);
        }
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, id));
        userAuthorityMapper.deleteById(id);
        return Boolean.TRUE;
    }

    /**
     * 保存用户信息
     *
     * @param userUpdateDto DTO 对象
     * @return success/fail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveLimitUser(UserLimitAddDto userUpdateDto) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userUpdateDto, sysUser);
        sysUser.setLockFlag(StrUtil.isBlank(userUpdateDto.getLockFlag()) ? UserStateEnum.NORMAL.getCode() : userUpdateDto.getLockFlag());
        sysUser.setCreateBy(userUpdateDto.getUsername());
        sysUser.setUpdateBy(userUpdateDto.getUsername());
        sysUser.setPasswordExpireFlag(UserStateEnum.NORMAL.getCode());
        //设置默认密码 用户名
        sysUser.setPassword(ENCODER.encode(userUpdateDto.getUsername()));
        sysUser.setDelFlag("0");
        sysUser.setCreateTime(LocalDateTime.now());
        // 判断手机号是否存在
        boolean phoneExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, userUpdateDto.getPhone()));
        if (phoneExists) {
            throw new OpenException(OpenResponseCode.USER_PHONE_IS_EXIST);
        }
        baseMapper.insert(sysUser);
        return Boolean.TRUE;
    }


    @Override
    public IPage getRoleName(Page page, String roleName) {
        Page<SysRole> sysRolePage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotBlank(roleName), SysRole::getRoleName, roleName);
        Page<SysRole> rolePage = sysRoleMapper.selectPage(sysRolePage, queryWrapper);
        rolePage.getRecords().forEach(a -> {
            a.setUserNumber(userAuthorityMapper.selectCount(Wrappers.<UserAuthority>lambdaQuery().eq(UserAuthority::getRoleId, a.getRoleId()).eq(UserAuthority::getStatus, "0").eq(UserAuthority::getDelFlag, "0")));
        });
        return rolePage;
    }

    @Override
    public List<UserDepartmentInfo> getAll() {
        return userDepartmentInfoMapper
                .selectList(Wrappers.<UserDepartmentInfo>lambdaQuery()
                        .eq(UserDepartmentInfo::getOrgStatus, 1));
    }

    @Override
    public List<UserSeal> getUserSealList() {
        return userSealMapper.selectList(null);
    }

    @Override
    public IPage getDeductionPage(Page page, DeductionPageDTO deductionPageDTO) {
        Page<SysUser> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(deductionPageDTO.getUserId() != null, SysUser::getUserId, deductionPageDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1").eq(StrUtil.isNotBlank(deductionPageDTO.getPhone()), SysUser::getPhone, deductionPageDTO.getPhone())
                .eq(StrUtil.isNotBlank(deductionPageDTO.getUserJobNumber()), SysUser::getUserJobNumber, deductionPageDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(deductionPageDTO.getGuid()), SysUser::getGuid, deductionPageDTO.getGuid())
                .eq(StrUtil.isNotBlank(deductionPageDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, deductionPageDTO.getUserMealsNumber())
                .orderByDesc(SysUser::getCreateTime);
        return this.page(sysUserPage, queryWrapper);
    }

    @Override
    public Boolean getDeduction(DeductionDTO deductionDTO) {
        RLock lock = redissonClient.getLock("getAccountLock" + deductionDTO.getGuid());
        try {
            // 直接获取锁，阻塞式
            lock.lock(10, TimeUnit.SECONDS);
            SysUser sysUser = sysUserMapper.selectByGuid(deductionDTO.getGuid());
            if (sysUser == null) {
                throw new OpenException(OpenResponseCode.USER_NO_EXIST);
            }

            if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
                throw new OpenException(OpenResponseCode.DEDUCTION_LOCK);
            }
            if (deductionDTO.getDeductionType() == 1) {
                if (sysUser.getCardState().equals("2")) {
                    throw new OpenException(OpenResponseCode.DEDUCTION_LOCK);
                }
                if (sysUser.getCardAccount() != null) {
                    if (deductionDTO.getDeductionMoney().compareTo(sysUser.getCardAccount()) > 0) {
                        throw new OpenException(OpenResponseCode.DEDUCTION);
                    }
                    sysUserMapper.deductionIncrByCardAccount(sysUser.getGuid(), deductionDTO.getDeductionMoney(), sysUser.getUpdateTime());
                }
            } else if (deductionDTO.getDeductionType() == 2) {
                if (sysUser.getCashState().equals("2")) {
                    throw new OpenException(OpenResponseCode.DEDUCTION_LOCK);
                }
                if (sysUser.getCashAccount() != null) {
                    if (deductionDTO.getDeductionMoney().compareTo(sysUser.getCashAccount()) > 0) {
                        throw new OpenException(OpenResponseCode.DEDUCTION);
                    }
                    sysUserMapper.deductionIncrByCashAccount(sysUser.getGuid(), deductionDTO.getDeductionMoney(), sysUser.getUpdateTime());
                }
            }

            String rechargeStream = UserTypeToNameUtil.setRechargeStream();
            UserPayment userDeduction = new UserPayment();
            //生成支付流水
            BeanUtils.copyProperties(sysUser, userDeduction);
            userDeduction.setAccountType(deductionDTO.getDeductionType().toString());
            userDeduction.setPaymentChannel("3");
            userDeduction.setTransactionTime(LocalDateTime.now());
            userDeduction.setRechargeStream(rechargeStream);
            if (deductionDTO.getDeductionType() == 1) {
                userDeduction.setCardAccount(sysUser.getCardAccount().subtract(deductionDTO.getDeductionMoney()));
                userDeduction.setCashAccount(sysUser.getCashAccount());
            }
            if (deductionDTO.getDeductionType() == 2) {
                userDeduction.setCardAccount(sysUser.getCardAccount());
                userDeduction.setCashAccount(sysUser.getCashAccount().subtract(deductionDTO.getDeductionMoney()));
            }
            if (StrUtil.isNotBlank(deductionDTO.getNotes())) {
                userDeduction.setNotes(deductionDTO.getNotes());
            }
            userDeduction.setPayNumber(deductionDTO.getDeductionMoney());
            userPaymentMapper.insert(userDeduction);
            UserTransaction userTransaction = new UserTransaction();
            BeanUtil.copyProperties(userDeduction, userTransaction);
            userTransaction.setTransactionNumber(deductionDTO.getDeductionMoney());
            userTransaction.setTransactionType("10");
            userTransaction.setTradeType(2);
            userTransaction.setUserMealsNumber(sysUser.getUserMealsNumber());
            userTransactionMapper.insert(userTransaction);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return Boolean.TRUE;
    }

    @Override
    public Boolean userState(UserStateDTO userStateDTO) {
        SysUser sysUser = sysUserMapper.selectByGuid(userStateDTO.getGuid());
        String state = null;
        if (sysUser.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            throw new OpenException(OpenResponseCode.LOCK_TO);
        }
        if (userStateDTO.getWallet() == 2) {
            if (Objects.equals(sysUser.getCardState(), "1")) {
                state = "2";
            }
            if (Objects.equals(sysUser.getCardState(), "2")) {
                state = "1";
            }
            sysUser.setCardState(state);
        } else if (userStateDTO.getWallet() == 3) {
            if (Objects.equals(sysUser.getCashState(), "1")) {
                state = "2";
            }
            if (Objects.equals(sysUser.getCashState(), "2")) {
                state = "1";
            }
            sysUser.setCashState(state);
        }
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);
        return Boolean.TRUE;
    }

    @Override
    public IPage getUsersWalletPage(Page page, WalletDTO walletDTO) {
        Page<SysUser> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber());
        if (StrUtil.isNotBlank(walletDTO.getState())) {
            if (Objects.equals(walletDTO.getState(), "1")) {
                // 正常
                queryWrapper.eq(SysUser::getCardState, walletDTO.getState())
                        .eq(SysUser::getCashState, walletDTO.getState());
            } else {
                queryWrapper.and(state -> state.eq(SysUser::getCardState, walletDTO.getState())
                        .or().eq(SysUser::getCashState, walletDTO.getState()));
            }
        }
        queryWrapper.orderByDesc(SysUser::getCreateTime);
        return this.page(sysUserPage, queryWrapper);
    }

    @Override
    public WalletVO getUsersWallet(WalletDTO walletDTO) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        WalletVO walletVO = new WalletVO();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber());
        if (walletDTO.getWallet() == 1) {
            if (StrUtil.isNotBlank(walletDTO.getState())) {
                if (Objects.equals(walletDTO.getState(), "1")) {
                    // 正常
                    queryWrapper.eq(SysUser::getCardState, walletDTO.getState())
                            .eq(SysUser::getCashState, walletDTO.getState());
                } else {
                    queryWrapper.eq(SysUser::getCardState, walletDTO.getState())
                            .or().eq(SysUser::getCashState, walletDTO.getState());
                }
            }
            queryWrapper.orderByDesc(SysUser::getCreateTime);
            List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
            List<BigDecimal> cardAccountList = sysUserList.stream().map(SysUser::getCardAccount).filter(Objects::nonNull).toList();
            List<BigDecimal> cashAccountList = sysUserList.stream().map(SysUser::getCashAccount).filter(Objects::nonNull).toList();
            BigDecimal cardAccountAll = cardAccountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal cashAccountAll = cashAccountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            walletVO.setAllAccount(cardAccountAll.add(cashAccountAll));
            walletVO.setCardAccount(cardAccountAll);
            walletVO.setCashAccount(cashAccountAll);
        } else if (walletDTO.getWallet() == 2) {
            queryWrapper.eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCardState, walletDTO.getState());
            List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
            BigDecimal cardAccountAll = sysUserList.stream().map(SysUser::getCardAccount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            walletVO.setAggregateBalance(cardAccountAll);
            walletVO.setCardNumber(sysUserList.size());
        } else if (walletDTO.getWallet() == 3) {
            queryWrapper.eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCashState, walletDTO.getState());
            List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
            BigDecimal cashAccountAll = sysUserList.stream().map(SysUser::getCashAccount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            walletVO.setAggregateBalance(cashAccountAll);
            walletVO.setCardNumber(sysUserList.size());
        }
        return walletVO;
    }

    @Override
    public IPage getUsersWalletMealPage(Page page, WalletDTO walletDTO) {
        Page<SysUser> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCardState, walletDTO.getState())
                .orderByDesc(SysUser::getCreateTime);
        return this.page(sysUserPage, queryWrapper);
    }

    @Override
    public IPage getUsersWalletCashPage(Page page, WalletDTO walletDTO) {
        Page<SysUser> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCashState, walletDTO.getState())
                .orderByDesc(SysUser::getCreateTime);
        return this.page(sysUserPage, queryWrapper);
    }

    /**
     * 通过查用户的全部信息
     *
     * @param sysUser 用户
     * @return
     */
    @Override
    public UserInfo findUserInfo(SysUser sysUser) {
        UserInfo userInfo = new UserInfo();
        userInfo.setSysUser(sysUser);
        // 设置角色列表 （ID）
        List<Long> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()).stream().map(SysRole::getRoleId).collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class));

        // 设置权限列表（menu.permission）
        Set<String> permissions = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<String> permissionList = sysMenuService.findMenuByRoleId(roleId).stream().filter(menu -> StrUtil.isNotEmpty(menu.getPermission())).map(SysMenu::getPermission).toList();
            permissions.addAll(permissionList);
        });
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
        return userInfo;
    }

    /**
     * 分页查询用户信息
     *
     * @param page        分页对象
     * @param userPageDTO 参数列表
     * @return
     */
    @Override
    public IPage getUsersWithRolePage(Page page, UserPageDTO userPageDTO) {
        Page<SysUser> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getIsAdmin, "1")
                .eq(SysUser::getDelFlag, "0")
                .like(StrUtil.isNotBlank(userPageDTO.getUserAccount()), SysUser::getUserAccount, userPageDTO.getUserAccount())
                .eq(userPageDTO.getUserId() != null, SysUser::getUserId, userPageDTO.getUserId())
                .like(StrUtil.isNotBlank(userPageDTO.getUsername()), SysUser::getUsername, userPageDTO.getUsername())
                .like(StrUtil.isNotBlank(userPageDTO.getGuid()), SysUser::getGuid, userPageDTO.getGuid())
                .eq(StrUtil.isNotBlank(userPageDTO.getUserJobNumber()), SysUser::getUserJobNumber, userPageDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(userPageDTO.getPhone()), SysUser::getPhone, userPageDTO.getPhone())
                .eq(StrUtil.isNotBlank(userPageDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, userPageDTO.getUserMealsNumber())
                .eq(userPageDTO.getRoleId() != null, SysUser::getRoleId, userPageDTO.getRoleId())
                .orderByDesc(SysUser::getCreateTime);
        return this.page(sysUserPage, queryWrapper);
    }

    @Override
    public IPage getUserAuthorityPage(Page page, UserPageDTO userPageDTO) {
        Page<UserAuthority> sysUserPage = new Page<>(page.getCurrent(), page.getSize());
        LambdaQueryWrapper<UserAuthority> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserAuthority::getDelFlag, "0")
                .eq(userPageDTO.getUserId() != null, UserAuthority::getUserId, userPageDTO.getUserId())
                .eq(StrUtil.isNotBlank(userPageDTO.getGuid()), UserAuthority::getGuid, userPageDTO.getGuid())
                .eq(StrUtil.isNotBlank(userPageDTO.getLockFlag()), UserAuthority::getStatus, userPageDTO.getLockFlag())
                .like(StrUtil.isNotBlank(userPageDTO.getUsername()), UserAuthority::getUsername, userPageDTO.getUsername())
                .eq(StrUtil.isNotBlank(userPageDTO.getPhone()), UserAuthority::getPhone, userPageDTO.getPhone())
                .eq(StrUtil.isNotBlank(userPageDTO.getGuid()), UserAuthority::getGuid, userPageDTO.getGuid())
                .eq(userPageDTO.getRoleId() != null, UserAuthority::getRoleId, userPageDTO.getRoleId())
                .orderByDesc(UserAuthority::getCreateTime);
        return userAuthorityMapper.selectPage(sysUserPage, queryWrapper);
    }

    @Override
    public UserAccountVO getUserNumber(UserPageDTO userPageDTO) {
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(userPageDTO, sysUser);
        List<SysUser> sysUserList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getIsAdmin, "1")
                .eq(userPageDTO.getUserId() != null, SysUser::getUserId, userPageDTO.getUserId())
                .like(StrUtil.isNotBlank(userPageDTO.getUserAccount()), SysUser::getUserAccount, userPageDTO.getUserAccount())
                .like(StrUtil.isNotBlank(userPageDTO.getUsername()), SysUser::getUsername, userPageDTO.getUsername())
                .eq(StrUtil.isNotBlank(userPageDTO.getUserJobNumber()), SysUser::getUserJobNumber, userPageDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(userPageDTO.getGuid()), SysUser::getGuid, userPageDTO.getGuid())
                .eq(StrUtil.isNotBlank(userPageDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, userPageDTO.getUserMealsNumber())
                .eq(StrUtil.isNotBlank(userPageDTO.getPhone()), SysUser::getPhone, userPageDTO.getPhone()).eq(SysUser::getDelFlag, "0"));
        if (sysUserList.isEmpty()) {
            // 用户表不存在数据
            throw new OpenException(OpenResponseCode.USER_NOT_IS_EXIST);
        }
        UserAccountVO userAccountVO = new UserAccountVO();
        userAccountVO.setAccountNumber(sysUserList.size());
//        用户类型1内部员工2委外员工3见习员工4充值无管理费人员5委外单位6食堂职工7其他8外部
        userAccountVO.setUserInside(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_INSIDE.getCode())).toList().size());
//        userAccountVO.setUserOutset(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_OUTSET.getCode())).toList().size());
//        userAccountVO.setUserProbation(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_PROBATION.getCode())).toList().size());
//        userAccountVO.setUserRecharge(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_RECHARGE.getCode())).toList().size());
//        userAccountVO.setUserBitUnit(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_BIT_UNIT.getCode())).toList().size());
//        userAccountVO.setUserCanteen(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_CANTEEN.getCode())).toList().size());
//        userAccountVO.setUserOther(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_OTHER.getCode())).toList().size());
//        userAccountVO.setUserExterior(sysUserList.stream().filter(a -> Objects.equals(a.getUserType(), UserTypeEnum.USER_EXTERIOR.getCode())).toList().size());
        userAccountVO.setCashAccountAll(sysUserMapper.selectAllCashAmount());
        userAccountVO.setCardAccountAll(sysUserMapper.selectAllCardAmount());
        return userAccountVO;
    }

    @Override
    public List<UserWalletExcelVO> getUsersWalletExcel(WalletDTO walletDTO) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber())
                .last(" limit 100000");
        if (StrUtil.isNotBlank(walletDTO.getState())) {
            if (Objects.equals(walletDTO.getState(), "1")) {
                // 正常
                queryWrapper.eq(SysUser::getCardState, walletDTO.getState()).eq(SysUser::getCashState, walletDTO.getState());
            } else {
                queryWrapper.eq(SysUser::getCardState, walletDTO.getState()).or().eq(SysUser::getCashState, walletDTO.getState());
            }
        }
        List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
        List<UserWalletExcelVO> userWalletExcelVOList = new ArrayList<>();
        AtomicInteger index = new AtomicInteger(1);
        sysUserList.forEach(a -> {
            UserWalletExcelVO userWalletExcelVO = new UserWalletExcelVO();
            BeanUtil.copyProperties(a, userWalletExcelVO);
            userWalletExcelVO.setIndex(index.getAndIncrement());
            userWalletExcelVO.setUserTypeName(UserTypeToNameUtil.getUserType(a.getUserType()));
            userWalletExcelVO.setCardState(a.getCardState().equals(UserCardStateEnum.NORMAL.getCode()) ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
            userWalletExcelVO.setCashState(a.getCashState().equals(UserCardStateEnum.NORMAL.getCode()) ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
            userWalletExcelVOList.add(userWalletExcelVO);
        });
        return userWalletExcelVOList;
    }

    @Override
    public List<UserCashExcelVO> getUsersCashExcel(WalletDTO walletDTO) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCashState, walletDTO.getState())
                .last(" limit 100000");
        AtomicInteger index = new AtomicInteger(1);
        List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
        List<UserCashExcelVO> userCashExcelVOList = new ArrayList<>();
        sysUserList.forEach(a -> {
            UserCashExcelVO userCashExcelVO = new UserCashExcelVO();
            BeanUtil.copyProperties(a, userCashExcelVO);
            userCashExcelVO.setIndex(index.getAndIncrement());
            userCashExcelVO.setUserTypeName(UserTypeToNameUtil.getUserType(a.getUserType()));
            userCashExcelVO.setCashState(a.getCashState().equals(UserCardStateEnum.NORMAL.getCode()) ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
            userCashExcelVOList.add(userCashExcelVO);
        });
        return userCashExcelVOList;
    }

    @Override
    public List<UserCardExcelVO> getUsersCardExcel(WalletDTO walletDTO) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(walletDTO.getUserId() != null, SysUser::getUserId, walletDTO.getUserId())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(walletDTO.getPhone()), SysUser::getPhone, walletDTO.getPhone())
                .eq(StrUtil.isNotBlank(walletDTO.getUserJobNumber()), SysUser::getUserJobNumber, walletDTO.getUserJobNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getGuid()), SysUser::getGuid, walletDTO.getGuid())
                .eq(StrUtil.isNotBlank(walletDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, walletDTO.getUserMealsNumber())
                .eq(StrUtil.isNotBlank(walletDTO.getState()), SysUser::getCardState, walletDTO.getState())
                .last(" limit 100000");
        List<SysUser> sysUserList = sysUserMapper.selectList(queryWrapper);
        List<UserCardExcelVO> userCashExcelVOList = new ArrayList<>();
        AtomicInteger index = new AtomicInteger(1);
        sysUserList.forEach(a -> {
            UserCardExcelVO userCardExcelVO = new UserCardExcelVO();
            BeanUtil.copyProperties(a, userCardExcelVO);
            userCardExcelVO.setIndex(index.getAndIncrement());
            userCardExcelVO.setUserTypeName(UserTypeToNameUtil.getUserType(a.getUserType()));
            userCardExcelVO.setCardState(a.getCardState().equals(UserCardStateEnum.NORMAL.getCode()) ? UserCardStateEnum.NORMAL.getDesc() : UserCardStateEnum.FREEZE.getDesc());
            userCashExcelVOList.add(userCardExcelVO);
        });
        return userCashExcelVOList;
    }

    @Override
    public List<UserLoadExcelVO> getUserExcel(UserPageDTO userPageDTO) {
        List<SysUser> userList = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                .eq(userPageDTO.getUserId() != null, SysUser::getUserId, userPageDTO.getUserId())
                .like(StrUtil.isNotBlank(userPageDTO.getUserAccount()), SysUser::getUserAccount, userPageDTO.getUserAccount())
                .like(StrUtil.isNotBlank(userPageDTO.getUsername()), SysUser::getUsername, userPageDTO.getUsername())
                .eq(StrUtil.isNotBlank(userPageDTO.getUserJobNumber()), SysUser::getUserJobNumber, userPageDTO.getUserJobNumber())
                .eq(SysUser::getIsAdmin, "1")
                .eq(StrUtil.isNotBlank(userPageDTO.getUserMealsNumber()), SysUser::getUserMealsNumber, userPageDTO.getUserMealsNumber())
                .eq(StrUtil.isNotBlank(userPageDTO.getGuid()), SysUser::getGuid, userPageDTO.getGuid())
                .eq(StrUtil.isNotBlank(userPageDTO.getPhone()), SysUser::getPhone, userPageDTO.getPhone()).eq(SysUser::getDelFlag, "0"));

        //获取公司和部门
        List<UserDepartmentInfo> userDepartmentInfoList = userDepartmentInfoMapper.selectList(null);

        //获取职务
        List<SysPost> sysPostList = sysPostMapper.selectList(null);

        List<UserLoadExcelVO> userExcelList = new ArrayList<>();
        AtomicInteger index = new AtomicInteger(1);
        userList.forEach(a -> {
            UserLoadExcelVO userExcelVO = new UserLoadExcelVO();
            BeanUtil.copyProperties(a, userExcelVO);
            userExcelVO.setIndex(index.getAndIncrement());
            if (a.getUserType() != null) {
                userExcelVO.setUserTypeName(UserTypeToNameUtil.getUserType(a.getUserType()));
            }
            if (!a.getLockFlag().isEmpty()) {
                userExcelVO.setLockFlag(a.getLockFlag().equals(UserStateEnum.NORMAL.getCode()) ? UserStateEnum.NORMAL.getDesc() : UserStateEnum.LOCK.getDesc());
            }
            if (a.getIsTheCard() != null) {
                userExcelVO.setIsTheCard(a.getIsTheCard().equals(UserCardEnum.NORMAL.getCode()) ? UserCardEnum.NORMAL.getDesc() : UserCardEnum.LOCK.getDesc());
            }

            List<UserDepartmentInfo> deptList = new ArrayList<>();
            if (a.getDeptId() != null) {
                deptList = userDepartmentInfoList.stream().filter(Objects::nonNull)
                        .filter(dd -> StrUtil.isNotBlank(dd.getDeptId()))
                        .filter(dd -> dd.getDeptId().equals(a.getThirdDeptId())).toList();
            }

            List<UserDepartmentInfo> companyList = new ArrayList<>();

            if (a.getCompanyId() != null) {
                companyList = userDepartmentInfoList.stream().filter(Objects::nonNull)
                        .filter(dd -> dd.getId().equals(a.getCompanyId())).toList();
            }

            List<SysPost> postList = new ArrayList<>();

            if (a.getPostId() != null) {
                postList = sysPostList.stream().filter(Objects::nonNull)
                        .filter(dd -> dd.getPostCode().equals(a.getPostId().toString())).toList();
            }

            if (!deptList.isEmpty()) {
                UserDepartmentInfo userDepartmentInfo = deptList.stream().findFirst().get();
                if (StrUtil.isNotBlank(userDepartmentInfo.getOrgShortName())) {
                    userExcelVO.setDeptName(userDepartmentInfo.getOrgShortName());
                }
            }

            if (!companyList.isEmpty()) {
                UserDepartmentInfo userCompany = companyList.stream().findFirst().get();
                if (StrUtil.isNotBlank(userCompany.getOrgShortName())) {
                    userExcelVO.setCompanyName(userCompany.getOrgShortName());
                }
            }
            if (!postList.isEmpty()) {
                SysPost sysPost = postList.stream().findFirst().get();
                if (StrUtil.isNotBlank(sysPost.getPostName())) {
                    userExcelVO.setPost(sysPost.getPostName());
                }
            }

            userExcelList.add(userExcelVO);
        });
        return userExcelList;
    }

    @Override
    public Boolean deleteUserById(Long id) {
        SysUser sysUser = new SysUser();
        sysUser.setDelFlag("1");
        sysUser.setUserId(id);
        //删除角色表中关联
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, id));
        sysUser.setPullStatus(1);
        return sysUserMapper.updateById(sysUser) > 0;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(UserUpdateDto userUpdateDto) {
        // 更新用户表信息
        SysUser sysUser = sysUserMapper.selectById(userUpdateDto.getUserId());
        //更新时 判断是否存在该用户 依据：手机号，工号 其中一个有就失败 判断手机号是否存在
        boolean userJobNumberExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getIsAdmin, "1").eq(SysUser::getPhone, userUpdateDto.getPhone()).eq(SysUser::getUserJobNumber, userUpdateDto.getUserJobNumber()).eq(SysUser::getDelFlag, "0"));
        if (userJobNumberExists) {
            if (userUpdateDto.getPhone().equals(sysUser.getPhone()) && userUpdateDto.getUserJobNumber().equals(sysUser.getUserJobNumber())) {
            } else {
                throw new OpenException(OpenResponseCode.USER_JOB_NUMBER_IS_EXIST);
            }
        }
        boolean userNameExists = this.exists(Wrappers.<SysUser>lambdaQuery()
                .eq(SysUser::getUsername, userUpdateDto.getUsername())
                .eq(SysUser::getIsAdmin, "1")
                .eq(SysUser::getDelFlag, "0"));
        if (userNameExists) {
            if (!userUpdateDto.getUsername().equals(sysUser.getUsername())) {
                throw new OpenException(OpenResponseCode.USER_NAME_IS_EXIST);
            }
        }
        BeanUtils.copyProperties(userUpdateDto, sysUser);
        sysUser.setUpdateTime(LocalDateTime.now());
        if (userUpdateDto.getDeptId() != null) {
            sysUser.setThirdDeptId(userUpdateDto.getThirdDeptId());
            sysUser.setDeptId(null);
        }
        sysUser.setUpdateBy(userUpdateDto.getUsername());
        if (userUpdateDto.getLockFlag().equals(UserStateEnum.LOCK.getCode())) {
            sysUser.setCashState("2");
            sysUser.setCardState("2");
        }
        sysUser.setPullStatus(1);

        this.updateById(sysUser);
        //tui
        clearToken(sysUser.getUsername());
        return Boolean.TRUE;
    }


    /**
     * 通过ID查询用户信息
     *
     * @param id 用户ID
     * @return 用户信息
     */
    @Override
    public UserDetailVO selectUserVoById(String id) {
        UserDetailVO userDetailVO = new UserDetailVO();
        SysUser sysUser = sysUserMapper.selectByGuid(id);
        BeanUtil.copyProperties(sysUser, userDetailVO);
        UserAuthority userAuthority = userAuthorityMapper
                .selectOne(Wrappers.<UserAuthority>lambdaQuery()
                        .eq(UserAuthority::getUserId, sysUser.getUserId())
                        .orderByDesc(UserAuthority::getCreateTime)
                        .last("limit 1"));
        if (sysUser.getThirdDeptId() == null) {
            UserDepartmentInfo userDepartmentInfo = userDepartmentInfoMapper.selectOne(Wrappers.<UserDepartmentInfo>lambdaQuery()
                    .eq(UserDepartmentInfo::getDeptId, sysUser.getThirdDeptId())
                    .last(" limit 1"));
            if (userDepartmentInfo != null && StrUtil.isNotBlank(userDepartmentInfo.getOrgShortName())) {
                userDetailVO.setThirdDeptId(userDepartmentInfo.getDeptId());
                userDetailVO.setDeptName(userDepartmentInfo.getOrgShortName());
            }
        }
        userDetailVO.setDeptId(null);
        if (sysUser.getCompanyId() != null) {
            userDetailVO.setCompanyId(sysUser.getCompanyId());
        }

        if (userAuthority != null) {
            userDetailVO.setStatus(userAuthority.getStatus());
            userDetailVO.setId(userAuthority.getId());
            userDetailVO.setRoleId(userAuthority.getRoleId());
        }
        return userDetailVO;
    }

    /**
     * 删除用户
     *
     * @param ids 用户ID 列表
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteUserByIds(Long[] ids) {
        // 删除 spring cache
        List<SysUser> userList = baseMapper.selectBatchIds(CollUtil.toList(ids));
        Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
        for (SysUser sysUser : userList) {
            cache.evict(sysUser.getUsername());
        }
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getUserId, CollUtil.toList(ids)));
        this.removeBatchByIds(CollUtil.toList(ids));
        return Boolean.TRUE;
    }

    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
    public R<Boolean> updateUserInfo(UserDTO userDto) {
        Long userId = SecurityUtils.getUser().getId();
        SysUser sysUser = new SysUser();
        sysUser.setPhone(userDto.getPhone());
        sysUser.setUserId(userId);
        sysUser.setAvatar(userDto.getAvatar());
        sysUser.setNickname(userDto.getNickname());
        sysUser.setName(userDto.getName());
        sysUser.setEmail(userDto.getEmail());
        return R.ok(this.updateById(sysUser));
    }

    /**
     * 查询上级部门的用户信息
     *
     * @param username 用户名
     * @return R
     */
    @Override
    public List<SysUser> listAncestorUsers(String username) {
        SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));

        SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
        if (sysDept == null) {
            return null;
        }

        Long parentId = sysDept.getParentId();
        return this.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, parentId));
    }

    /**
     * 查询全部的用户
     *
     * @param userDTO 查询条件
     * @param ids     ids 用户列表
     * @return list
     */
    @Override
    public List<UserExcelVO> listUser(UserDTO userDTO, Long[] ids) {
//        // 根据数据权限查询全部的用户信息
//        List<UserVO> voList = baseMapper.selectVoListByScope(userDTO, ids, DataScope.of());
//        // 转换成execl 对象输出
//        List<UserExcelVO> userExcelVOList = voList.stream().map(userVO -> {
//            UserExcelVO excelVO = new UserExcelVO();
//            BeanUtils.copyProperties(userVO, excelVO);
//            String roleNameList = userVO.getRoleList().stream().map(SysRole::getRoleName).collect(Collectors.joining(StrUtil.COMMA));
//            excelVO.setRoleNameList(roleNameList);
//            String postNameList = userVO.getPostList().stream().map(SysPost::getPostName).collect(Collectors.joining(StrUtil.COMMA));
//            excelVO.setPostNameList(postNameList);
//            return excelVO;
//        }).collect(Collectors.toList());
//        return userExcelVOList;
        return null;
    }

    /**
     * excel 导入用户, 插入正确的 错误的提示行号
     *
     * @param excelVOList   excel 列表数据
     * @param bindingResult 错误数据
     * @return ok fail
     */
    @Override
    public R importUser(List<UserExcelVO> excelVOList, BindingResult bindingResult) {
        // 通用校验获取失败的数据
//        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
//        List<SysDept> deptList = sysDeptService.list();
//        List<SysRole> roleList = sysRoleService.list();
//        List<SysPost> postList = sysPostService.list();
//
//        // 执行数据插入操作 组装 UserDto
//        for (UserExcelVO excel : excelVOList) {
//            // 个性化校验逻辑
//            List<SysUser> userList = this.list();
//
//            Set<String> errorMsg = new HashSet<>();
//            // 校验用户名是否存在
//            boolean exsitUserName = userList.stream().anyMatch(sysUser -> excel.getUsername().equals(sysUser.getUsername()));
//
//            if (exsitUserName) {
//                errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, excel.getUsername()));
//            }
//
//            // 判断输入的部门名称列表是否合法
//            Optional<SysDept> deptOptional = deptList.stream().filter(dept -> excel.getDeptName().equals(dept.getName())).findFirst();
//            if (!deptOptional.isPresent()) {
//                errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_DEPT_DEPTNAME_INEXISTENCE, excel.getDeptName()));
//            }
//
//            // 判断输入的角色名称列表是否合法
//            List<String> roleNameList = StrUtil.split(excel.getRoleNameList(), StrUtil.COMMA);
//            List<SysRole> roleCollList = roleList.stream().filter(role -> roleNameList.stream().anyMatch(name -> role.getRoleName().equals(name))).collect(Collectors.toList());
//
//            if (roleCollList.size() != roleNameList.size()) {
//                errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_ROLE_ROLENAME_INEXISTENCE, excel.getRoleNameList()));
//            }
//
//            // 判断输入的部门名称列表是否合法
//            List<String> postNameList = StrUtil.split(excel.getPostNameList(), StrUtil.COMMA);
//            List<SysPost> postCollList = postList.stream().filter(post -> postNameList.stream().anyMatch(name -> post.getPostName().equals(name))).collect(Collectors.toList());
//
//            if (postCollList.size() != postNameList.size()) {
//                errorMsg.add(MsgUtils.getMessage(ErrorCodes.SYS_POST_POSTNAME_INEXISTENCE, excel.getPostNameList()));
//            }
//
//            // 数据合法情况
//            if (CollUtil.isEmpty(errorMsg)) {
//                insertExcelUser(excel, deptOptional, roleCollList, postCollList);
//            } else {
//                // 数据不合法情况
//                errorMessageList.add(new ErrorMessage(excel.getLineNum(), errorMsg));
//            }
//
//        }
//
//        if (CollUtil.isNotEmpty(errorMessageList)) {
//            return R.failed(errorMessageList);
//        }
        return R.ok(null, MsgUtils.getMessage(ErrorCodes.SYS_USER_IMPORT_SUCCEED));
    }

    /**
     * 插入excel User
     */
    private void insertExcelUser(UserExcelVO excel, Optional<SysDept> deptOptional, List<SysRole> roleCollList, List<SysPost> postCollList) {
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(excel.getUsername());
        userDTO.setPhone(excel.getPhone());
        userDTO.setNickname(excel.getNickname());
        userDTO.setName(excel.getName());
        userDTO.setEmail(excel.getEmail());
        userDTO.setLockFlag(excel.getLockFlag());
        // 批量导入初始密码为手机号
        userDTO.setPasswordModifyTime(LocalDateTime.now());
        userDTO.setPassword(userDTO.getPhone());
        // 根据部门名称查询部门ID
        userDTO.setDeptId(deptOptional.get().getDeptId());
        // 插入岗位名称
        List<Long> postIdList = postCollList.stream().map(SysPost::getPostId).toList();
//        userDTO.setPost(postIdList);
        // 根据角色名称查询角色ID
        List<Long> roleIdList = roleCollList.stream().map(SysRole::getRoleId).collect(Collectors.toList());
        userDTO.setRole(roleIdList);
        // 插入用户
        UserAddDto userUpdateDto = new UserAddDto();
        BeanUtil.copyProperties(userDTO, userUpdateDto);
        this.saveUser(userUpdateDto);
    }

    /**
     * 注册用户 赋予用户默认角色
     *
     * @param userDto 用户信息
     * @return success/false
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> registerUser(UserDTO userDto) {
        // 判断用户名是否存在
        boolean usernameExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, userDto.getUsername()));
        if (usernameExists) {
            String message = MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, userDto.getUsername());
            return R.failed(message);
        }

        // 判断手机号是否存在
        boolean phoneExists = this.exists(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getPhone, userDto.getPhone()));
        if (phoneExists) {
            String message = MsgUtils.getMessage(ErrorCodes.SYS_USER_PHONE_EXISTING, userDto.getPhone());
            return R.failed(message);
        }
        UserAddDto userUpdateDto = new UserAddDto();
        BeanUtil.copyProperties(userDto, userUpdateDto);
        return R.ok(saveUser(userUpdateDto));
    }

    /**
     * 锁定用户
     *
     * @param username 用户名
     * @return
     */
    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#username")
    public R<Boolean> lockUser(String username) {
        SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username).orderByDesc(SysUser::getCreateTime).last("limit 1"));

        if (Objects.nonNull(sysUser)) {
            sysUser.setLockFlag(UserStateEnum.LOCK.getCode());
            baseMapper.updateById(sysUser);
        }
        return R.ok();
    }

    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
    public R changePassword(UserDTO userDto) {
        SysUser user = baseMapper.selectById(SecurityUtils.getUser().getId());
        if (StrUtil.isEmpty(userDto.getPassword())) {
            return R.failed("原密码不能为空");
        }

        if (!ENCODER.matches(userDto.getPassword(), user.getPassword())) {
            log.info("原密码错误，修改个人信息失败:{}", userDto.getUsername());
            return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_UPDATE_PASSWORDERROR));
        }

        if (StrUtil.isEmpty(userDto.getNewpassword1())) {
            return R.failed("新密码不能为空");
        }

        //正则表达式校验
        Pattern pattern = Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$");
        if (!pattern.matcher(userDto.getNewpassword1()).matches()) {
            return R.failed("新密码不符合规则,密码长度为8到20位,必须包含大小写字母和数字");
        }
        String password = ENCODER.encode(userDto.getNewpassword1());

        this.update(Wrappers.<SysUser>lambdaUpdate().set(SysUser::getPassword, password).set(SysUser::getPasswordModifyTime, LocalDateTime.now()).eq(SysUser::getUserId, user.getUserId()));
        return R.ok();
    }

    @Override
    public R unbinding(String type) {
        ScsUser user = SecurityUtils.getUser();
        LambdaUpdateWrapper<SysUser> wrapper = null;
        if (type.equals("wechat")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getWxOpenid, null).eq(SysUser::getUserId, user.getId());
        } else if (type.equals("gitee")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getGiteeLogin, null).eq(SysUser::getUserId, user.getId());
        } else if (type.equals("osc")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getOscId, null).eq(SysUser::getUserId, user.getId());
        } else if (type.equals("tencent")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getQqOpenid, null).eq(SysUser::getUserId, user.getId());
        } else if (type.equals("cp")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getWxCpUserid, null).eq(SysUser::getUserId, user.getId());
        } else if (type.equals("dingding")) {
            wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getWxDingUserid, null).eq(SysUser::getUserId, user.getId());
        }
        if (wrapper == null) {
            return R.failed("解绑账号类型不存在");
        }
        this.update(wrapper);
        return R.ok();
    }

    @Override
    public R checkPassword(String username, String password) {
        SysUser condition = new SysUser();
        condition.setUsername(username);
        SysUser sysUser = this.getOne(new QueryWrapper<>(condition));

        if (!ENCODER.matches(password, sysUser.getPassword())) {
            log.info("原密码错误");
            return R.failed("密码输入错误");
        } else {
            return R.ok();
        }
    }

    /**
     * 重置用户密码
     *
     * @param userDto 用户信息
     * @return
     */
    @Override
    @CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
    public R<Boolean> resetUserPassword(UserDTO userDto) {
        // 校验密码
        R checkedPassword = checkPassword(userDto.getUsername(), userDto.getPassword());
        if (!checkedPassword.isOk()) {
            return checkedPassword;
        }

        // 新密码校验
        if (StrUtil.equals(userDto.getPassword(), userDto.getNewpassword1())) {
            return R.failed("新旧密码不能相同");
        }

        // 重置密码
        String password = ENCODER.encode(userDto.getNewpassword1());
        this.update(Wrappers.<SysUser>lambdaUpdate().set(SysUser::getPassword, password).set(SysUser::getPasswordModifyTime, LocalDateTime.now()).set(SysUser::getPasswordExpireFlag, CommonConstants.STATUS_NORMAL).eq(SysUser::getUsername, userDto.getUsername()));
        return R.ok();
    }


    @Override
    public Boolean resetPassword(String guid) {
        //重置密码
        String password = ENCODER.encode("Aa1234567");
        sysUserMapper.updateByGuid(guid,password);
        return Boolean.TRUE;
    }

    @Override
    public Boolean updatePassword(UpdatePasswordDTO updatePasswordDTO) {
        //先对照旧密码是否相同
        SysUser sysUser = sysUserMapper.selectById(updatePasswordDTO.getUserId());
        if (!ENCODER.matches(updatePasswordDTO.getOldPassword(), sysUser.getPassword())) {
            throw new OpenException(OpenResponseCode.PASSWORD_ERROR);
        }
        sysUser.setPassword(ENCODER.encode(updatePasswordDTO.getNewPassword()));
        sysUser.setPullStatus(1);
        sysUser.setCardAccount(null);//不修改此字段
        sysUser.setCashAccount(null);//不修改此字段
        sysUserMapper.updateById(sysUser);
        return Boolean.TRUE;
    }

    @Override
    public List<Long> listUserIdByRoleIds(List<Long> roleIdList) {
        return sysUserRoleMapper.selectList(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getRoleId, roleIdList)).stream().map(SysUserRole::getUserId).collect(Collectors.toList());
    }

    /**
     * 根据部门ID列表获取用户ID列表接口
     *
     * @param deptIdList 部门ID列表
     * @return List<Long> 返回结果对象，包含根据部门ID列表获取到的用户ID列表信息
     */
    @Override
    public List<SysUser> listUserIdByDeptIds(List<Long> deptIdList) {
        return baseMapper.selectList(Wrappers.<SysUser>lambdaQuery().in(SysUser::getDeptId, deptIdList));
    }

    @Override
    public void updateByGuid(SysUser sysUser) {
        LambdaUpdateWrapper<SysUser> wrapper = Wrappers.<SysUser>lambdaUpdate().eq(SysUser::getGuid, sysUser.getGuid());
        baseMapper.update(sysUser, wrapper);
    }

    public void clearToken(String username) {
        // 根据分页参数获取对应数据
        String key = String.format("1::token::username::%s::*", username);
        Set<String> keys = redisTemplate.keys(key);
        assert keys != null;
        for (String item : keys) {
            //token
            String token = item.substring(item.lastIndexOf(":") + 1);
            log.info("删除redis >>> key:{}", item);
            redisTemplate.delete("1::token::access_token::" + token);
            redisTemplate.delete(item);
        }
    }

}
